/*
 * formulation.c
 *
 *  Created on: 30/12/2011
 *      Author: marcio
 */

#include "formulation.h"

CPXENVptr env;//ambiente do cplex
CPXLPptr prob;//problema inteiro
long** varToEdge;//mapeamento de variavel para aresta
long**** edgeToVar;//mapeamento de aresta para variavel
long var;//numero de variaveis;

extern long k;//o k da coloração
extern long* va;//a ordem dos vertices



/*Inicializa o ambiente*/
int init(){
	setAdjMatrix(getSharedGraph());
	var = 0;
	long i,l,j,m;

	//alocação de memoria pra edgeVar
	edgeToVar = malloc(sizeof(long***)*nverts());
	for(i = 0; i < nverts(); i++){
		edgeToVar[va[i]] = malloc(sizeof(long**)*nverts());
		for(j = i; j < nverts(); j++){
			edgeToVar[va[i]][va[j]] = malloc(sizeof(long*)*k);
			for(l = 0; l < k; l++){
				edgeToVar[va[i]][va[j]][l] = malloc(sizeof(long)*k);
			}
		}
	}

	//alocação de memoria para verToedge
	varToEdge = malloc(sizeof(long*)*nverts()*nverts()*k);
	for(i = 0; i < nverts()*nverts()*k; i++){
		varToEdge[i] = malloc(sizeof(long)*4);
	}

	for(i = 0; i < nverts(); i++){
		for(l = 0; l < k; l++){
			for(m = 0; m < k; m++){
				edgeToVar[va[i]][va[i]][l][m] = var;
				varToEdge[var][0] = va[i];
				varToEdge[var][1] = va[i];
				varToEdge[var][2] = l;
				varToEdge[var][3] = l;
			}
			var++;
		}
		for(j = i+1; j < nverts(); j++){
			if(hasEdge(va[i], va[j])){
				for(l = 0; l < k; l++){
					for(m = 0; m < k; m++){
						edgeToVar[va[i]][va[j]][l][m] = var;
						varToEdge[var][0] = va[i];
						varToEdge[var][1] = va[j];
						varToEdge[var][2] = l;
						varToEdge[var][3] = m;
						var++;
						//printf("var = %d é referente a %d %d %d %d \n", var, va[i]+1, va[j]+1, l, m);
					}
				}
			}
		}
	}

	int status;
	env = CPXopenCPLEX(&status);
	prob = CPXcreateprob(env, &status, "Formulação de k-col!!!");
	double obj[var];
	double lb[var];
	double ub[var];
	char type[var];
	for(i = 0; i < var; i++){
		obj[i] = varToEdge[i][1] == varToEdge[i][0]? 1.0 : 0.0;
		lb[i] = 0.0;
		ub[i] = 1.0;
		type[i] = 'C';
	}
	//cria as variavies
	CPXnewcols(env, prob, var, obj, lb, ub, type, NULL);
	//defini o sentindo da função objetivo
	CPXchgobjsen(env, prob, CPX_MIN);
	CPXchgprobtype(env, prob, CPXPROB_LP);
	return 0;
}

/*adiciona restrição na anti-vizinhança de v referente a u e w*/
int addEdgeConstrain(long v, long u, long w){
	setAdjMatrix(getSharedGraph());
	int l, m, j;
	for(l = 0; l < k; l++){
		for(m = 0; m < k; m++){
			for(j = 0; j < k; j++){
				double rhs[1] = {0.0};//lado direito da restriçao
				char sense[1] = {'L'};// sentido da restriçao
				int rmatbeg[3] = {0,3};
				int rmatind[3];
				rmatind[0] = edgeToVar[v][u][l][m];
				rmatind[1] = edgeToVar[v][w][l][j];
				rmatind[2] = edgeToVar[v][v][l][l];
				double rmatval[3] = {1.0, 1.0, -1.0};
				CPXaddrows(env, prob, 0, 1, 3, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
			}
		}
	}
	return 0;
}

/*adiciona restrição de aresta a u e v*/
int addIndConstrain(long v, long u){
	setAdjMatrix(getSharedGraph());
	int l,m;
	for(l = 0; l < k; l++){
		for(m = 0; m < k; m++){
			double rhs[1] = {0.0};//lado direito da restriçao
			char sense[1] = {'L'};// sentido da restriçao
			int rmatbeg[2] = {0,2};
			int rmatind[2];
			rmatind[0] = edgeToVar[v][u][l][m];
			rmatind[1] = edgeToVar[v][v][l][l];
			double rmatval[2] = { 1.0, -1.0};
			CPXaddrows(env, prob, 0, 1, 2, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
		}
	}
	return 0;
}

/*Adiciona restrição de Cover referente a v*/
int addCoverConstrain(long v){
	setAdjMatrix(getSharedGraph());
	int i, l, m, num = 0;
	double rhs[1] = {1};//lado direito da restriçao
	char sense[1] = {'G'};// sentido da restriçao
	int rmatbeg[2];
	int rmatind[nverts()*k*k];
	double rmatval[nverts()*k*k];

	for(l = 0; l < k; l++){
		num = 0;
		rmatval[num] = 1.0;
		rmatind[num] = edgeToVar[va[v]][va[v]][l][l];
		num++;
		for(i = 0; i < v; i++){
			if(hasEdge(va[v], va[i])){
				for(m = 0; m < k; m++){
					rmatval[num] = 1.0;
					rmatind[num] = edgeToVar[va[i]][va[v]][m][l];
					num++;
				}
			}
		}
		rmatbeg[0] = 0;
		rmatbeg[1] = num;
		CPXaddrows(env, prob, 0, 1, num, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	}
	return 0;
}

int addCliqueConstrain(long v, long u){
	setAdjMatrix(getSharedGraph());
	int l,m,j;
	for(l = 0; l < k; l++){
		for(m = 0; m < k; m++){
			for(j = m+1; j < k; j++){
				double rhs[1] = {0.0};//lado direito da restriçao
				char sense[1] = {'L'};// sentido da restriçao
				int rmatbeg[2] = {0,3};
				int rmatind[3];
				rmatind[0] = edgeToVar[v][u][l][m];
				rmatind[1] = edgeToVar[v][u][l][j];
				rmatind[2] = edgeToVar[v][v][l][l];
				double rmatval[3] = { 1.0, 1.0, -1.0};
				CPXaddrows(env, prob, 0, 1, 3, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
			}
		}
	}
}

